﻿#if SILVERLIGHT

// ===================================
// <copyright>LogoUI Co.</copyright>
// <author>Vlad Spivak</author>
// <email>mailto:vlads@logoui.co.il</email>
// <created>20/00/10</created>
// <lastedit>Tuesday, November 23, 2010</lastedit>

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
// <remarks>Part of this software based on various internet sources, mostly on the works
// of members of Wpf Disciples group http://wpfdisciples.wordpress.com/
// Also project may contain code from works of Nito and OpenLight group</remarks>
// ====================================================================================//

#if SILVERLIGHT
using System.Windows.Markup;
using LogoFX.Composition;
using MefContrib.Hosting.Generics;
using Microsoft.ComponentModel.Composition.Hosting;
#endif
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.ReflectionModel;
using System.Linq;
using System.Reflection;
using AttributedModelServices = System.ComponentModel.Composition.AttributedModelServices;

namespace Caliburn.Micro
{
    /// <summary>
    /// MEF Enabled <c>Bootstrapper</c>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [ContentProperty("CatalogConfig")]
    public partial class MefBootstrapper<T> : BootstrapperBase<T>
    {
        protected CompositionContainer _container;

        DeploymentCatalogLoader _loader = new DeploymentCatalogLoader();

        /// <summary>
        /// Gets or sets the catalog configuration.
        /// </summary>
        /// <value>
        /// The catalog config.
        /// </value>
        public DeploymentCatalogConfig CatalogConfig
        {
            get { return _loader.CatalogConfig; }
            set { _loader.CatalogConfig = value; }
        }


        /// <summary>
        /// Override to configure the framework and setup your IoC container.
        /// </summary>
        protected sealed override void Configure()
        {            
            _loader.CatalogCached += (unused, args) => args.Catalog.Parts
                                                         .Select(part =>ReflectionModelServices.GetPartType(part).Value.Assembly)
                                                         .Where(assembly => !AssemblySource.Instance.Contains(assembly))
                                                         .Apply(a => AssemblySource.Instance.Add(a));

            DeploymentCatalog dc = new DeploymentCatalog();

            CompositionHostEx.Initialize(_loader.LoadCatalogConfigAsync(new GenericCatalog(dc,new GenericContractRegistry())));
            _container = CompositionHostEx.GetContainer();

            var batch = new CompositionBatch();
            batch.AddExportedValue<IWindowManager>(new WindowManager());
            batch.AddExportedValue<IEventAggregator>(new EventAggregator());
            batch.AddExportedValue(_container);

            OnConfigure(batch);            
            
            _container.Compose(batch);

            OnConfigureCompleted();
        }

        /// <summary>
        /// Configure ends
        /// </summary>
        protected virtual void OnConfigureCompleted()
        {
            
        }

        /// <summary>
        /// Provides chance to derived classes to add their own exports
        /// </summary>
        /// <param name="batch"></param>
        protected virtual void OnConfigure(CompositionBatch batch)
        {
            
        }

        /// <summary>
        /// Override this to provide an IoC specific implementation.
        /// </summary>
        /// <param name="service">The service to locate.</param>
        /// <param name="key">The key to locate.</param>
        /// <returns>The located service.</returns>
        protected override object GetInstance(Type serviceType, string key)
        {


            string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
            var exports = _container.GetExportedValues<object>(contract);

            if (exports.Count() > 0)
                return exports.First();

            throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
        }

        /// <summary>
        /// Override this to add custom behavior to execute after the application starts.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The args.</param>
        protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
        {

            //delay load of root view till all relewant modules are loaded
            if (CatalogConfig != null)
            {
                EventHandler loadAction = null;
                loadAction = (s, a) =>
                {
                    _loader.ConfigLoaded -= loadAction;
                    Execute.OnUIThread(DisplayRootView);
                };

                _loader.ConfigLoaded += loadAction;
                DeploymentCatalogLoader.ConfigLoadHelper loadHelper = new DeploymentCatalogLoader.ConfigLoadHelper(CatalogConfig);
                loadHelper.LoadAsync(_loader.OnLoaded, _loader.OnGroupLoaded, _loader.OnItemLoaded);
            }
            else
            {
                base.OnStartup(sender,e);
            }
        }

        /// <summary>
        /// Override this to provide an IoC specific implementation
        /// </summary>
        /// <param name="service">The service to locate.</param>
        /// <returns>The located services.</returns>
        protected override IEnumerable<object> GetAllInstances(Type serviceType)
        {
            return _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
        }

        /// <summary>
        /// Override this to provide an IoC specific implementation.
        /// </summary>
        /// <param name="instance">The instance to perform injection on.</param>
        protected override void BuildUp(object instance)
        {
            _container.SatisfyImportsOnce(instance);
        }

        /// <summary>
        /// Override to tell the framework where to find assemblies to inspect for views, etc.
        /// </summary>
        /// <returns>A list of assemblies to inspect.</returns>
        protected override IEnumerable<Assembly> SelectAssemblies()
        {
            return new[] {Assembly.GetExecutingAssembly(),typeof(IWindowManager).Assembly};
        }
    }
}
#endif